﻿using CCSSolderUI.Common.Event;
using CCSSolderUI.Models;
using HalconDotNet;
using Newtonsoft.Json;
using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;
using Prism.Services.Dialogs;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using ViewROI;

namespace CCSSolderUI.ViewModels.Dialogs
{
    public class CameraOperationDialogViewModel : BindableBase, IDialogAware
    {
        #region 导航
        private string title = "相机操作";
        public string Title
        {
            get { return title; }
            set { SetProperty(ref title, value); }
        }

        public event Action<IDialogResult> RequestClose;

        public bool CanCloseDialog()
        {
            return true;
        }

        public void OnDialogClosed()
        {
            if (source != null)
            {
                source.Cancel();
            }
            GTSCard.Instance.SetDo(2, 1);
        }

        public void OnDialogOpened(IDialogParameters parameters)
        {
            GTSCard.Instance.SetDo(2, 0);
            partNumber = parameters.GetValue<string>("PartNumber");
            LoadParam();
            AreaMaxThreshold = param.AreaMaxThreshold;
            AreaMinThreshold = param.AreaMinThreshold;
            distance = parameters.GetValue<double>("Distance");
            standZ = parameters.GetValue<double>("StandZ");
            hand = parameters.GetValue<int>("Hand");
            switch (hand)
            {
                case 0:
                    Title += "底板1";
                    break;
                default:
                    Title += "底板2";
                    break;
            }
            Update(partNumber);
        }
        #endregion
        #region 变量
        string partNumber = "";
        int hand = 0;double distance = 0; Param param;double standZ = 0;
        private readonly IEventAggregator _eventAggregator;
        CancellationTokenSource source;
        #endregion
        #region 属性
        private HImage cameraIamge0;
        public HImage CameraIamge0
        {
            get { return cameraIamge0; }
            set { SetProperty(ref cameraIamge0, value); }
        }
        private bool cameraRepaint0;
        public bool CameraRepaint0
        {
            get { return cameraRepaint0; }
            set { SetProperty(ref cameraRepaint0, value); }
        }
        private ObservableCollection<ROI> cameraROIList0 = new ObservableCollection<ROI>();
        public ObservableCollection<ROI> CameraROIList0
        {
            get { return cameraROIList0; }
            set { SetProperty(ref cameraROIList0, value); }
        }
        private HObject cameraAppendHObject0;
        public HObject CameraAppendHObject0
        {
            get { return cameraAppendHObject0; }
            set { SetProperty(ref cameraAppendHObject0, value); }
        }
        private HMsgEntry cameraAppendHMessage0;
        public HMsgEntry CameraAppendHMessage0
        {
            get { return cameraAppendHMessage0; }
            set { SetProperty(ref cameraAppendHMessage0, value); }
        }
        private Tuple<string, object> cameraGCStyle0;
        public Tuple<string, object> CameraGCStyle0
        {
            get { return cameraGCStyle0; }
            set { SetProperty(ref cameraGCStyle0, value); }
        }
        private ObservableCollection<MPoint> points = new ObservableCollection<MPoint>();
        public ObservableCollection<MPoint> Points
        {
            get { return points; }
            set { SetProperty(ref points, value); }
        }
        private double areaMinThreshold;
        public double AreaMinThreshold
        {
            get { return areaMinThreshold; }
            set { SetProperty(ref areaMinThreshold, value); }
        }
        private double areaMaxThreshold;
        public double AreaMaxThreshold
        {
            get { return areaMaxThreshold; }
            set { SetProperty(ref areaMaxThreshold, value); }
        }
        private bool isLiveGrab = false;
        public bool IsLiveGrab
        {
            get { return isLiveGrab; }
            set { SetProperty(ref isLiveGrab, value); }
        }
        #endregion
        #region 方法绑定
        private DelegateCommand<object> cameraOperateCommand;
        public DelegateCommand<object> CameraOperateCommand =>
            cameraOperateCommand ?? (cameraOperateCommand = new DelegateCommand<object>(ExecuteCameraOperateCommand));
        private DelegateCommand createShapModelCommand;
        public DelegateCommand CreateShapModelCommand =>
            createShapModelCommand ?? (createShapModelCommand = new DelegateCommand(ExecuteCreateShapModelCommand));
        private DelegateCommand<object> findShapModelCommand;
        public DelegateCommand<object> FindShapModelCommand =>
            findShapModelCommand ?? (findShapModelCommand = new DelegateCommand<object>(ExecuteFindShapModelCommand));
        private DelegateCommand<object> calculateCommand;
        public DelegateCommand<object> CalculateCommand =>
            calculateCommand ?? (calculateCommand = new DelegateCommand<object>(ExecuteCalculateCommand));
        private DelegateCommand saveButtonCommand;

        public DelegateCommand SaveButtonCommand =>
            saveButtonCommand ?? (saveButtonCommand = new DelegateCommand(ExecuteSaveButtonCommand));
        private DelegateCommand liveGrabCommand;
        public DelegateCommand LiveGrabCommand =>
            liveGrabCommand ?? (liveGrabCommand = new DelegateCommand(ExecuteLiveGrabCommand));

        void ExecuteLiveGrabCommand()
        {
            if (IsLiveGrab)
            {
                Camera.Instance.GrabeImageStart();
                source = new CancellationTokenSource();
                CancellationToken token = source.Token;
                Task.Run(() => ContinueGrab(token), token).ContinueWith(t => { Camera.Instance.GrabImage(); });
            }
            else
            {
                if (source != null)
                {
                    source.Cancel();
                }
                
            }
        }

        void ExecuteSaveButtonCommand()
        {
            param.AreaMinThreshold = AreaMinThreshold;
            param.AreaMaxThreshold = AreaMaxThreshold;
            try
            {
                string jsonString = JsonConvert.SerializeObject(param, Formatting.Indented);
                File.WriteAllText(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, partNumber, "Param.json"), jsonString);
                MessageBox.Show("保存完成", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
                _eventAggregator.GetEvent<MessagePrintEvent>().Publish(new Common.Event.Message() { Sender = "CameraOperationDialog", Type = "Update", Content = null });
            }
            catch (Exception ex)
            {
                _eventAggregator.GetEvent<MessagePrintEvent>().Publish(new Common.Event.Message() { Sender = "CameraOperationDialog", Type = "Print", Content = ex.Message });
            }
        }
        void ExecuteCalculateCommand(object obj)
        {
            try
            {
                // Local iconic variables 

                HObject ho_Image, ho_Region, ho_RegionErosion;
                HObject ModelRegion, ho_ConnectedRegions, ho_SelectedRegions, ho_RegionFillUp;

                // Initialize local and output iconic variables 
                HOperatorSet.GenEmptyObj(out ho_Image);
                HOperatorSet.GenEmptyObj(out ho_Region);
                HOperatorSet.GenEmptyObj(out ModelRegion);
                HOperatorSet.GenEmptyObj(out ho_RegionErosion);
                HOperatorSet.GenEmptyObj(out ho_ConnectedRegions);
                HOperatorSet.GenEmptyObj(out ho_SelectedRegions);
                HOperatorSet.GenEmptyObj(out ho_RegionFillUp);

                HOperatorSet.ReadRegion(out ModelRegion, System.IO.Path.Combine(System.Environment.CurrentDirectory, partNumber, "ModelRegion.hobj"));
                HOperatorSet.ReduceDomain(CameraIamge0, ModelRegion, out ho_Image);
                ho_Region.Dispose();
                HOperatorSet.Threshold(ho_Image, out ho_Region, 200, 255);
                ho_RegionErosion.Dispose();
                HOperatorSet.ErosionCircle(ho_Region, out ho_RegionErosion, 1);
                ho_ConnectedRegions.Dispose();
                HOperatorSet.Connection(ho_RegionErosion, out ho_ConnectedRegions);
                ho_SelectedRegions.Dispose();
                HOperatorSet.SelectShape(ho_ConnectedRegions, out ho_SelectedRegions, "area",
                    "and", AreaMinThreshold, AreaMaxThreshold);
                ho_RegionFillUp.Dispose();
                HOperatorSet.FillUp(ho_SelectedRegions, out ho_RegionFillUp);

                HTuple number;
                HOperatorSet.CountObj(ho_SelectedRegions, out number);
                HTuple area = null, row = null, column = null;
                HTuple row1 = null, column1 = null, phi = null, length1 = null, length2 = null;
                if (number.I > 1)
                {
                    MessageBox.Show("找到多个模板", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else if (number.I == 0)
                {
                    MessageBox.Show("未找到模板", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {

                    HOperatorSet.AreaCenter(ho_SelectedRegions, out area, out row, out column);

                    
                    HOperatorSet.SmallestRectangle2(ho_RegionFillUp, out row1, out column1, out phi, out length1, out length2);
                    HObject rec2;
                    HOperatorSet.GenEmptyObj(out rec2);
                    HOperatorSet.GenRectangle2(out rec2, row1, column1, phi, length1, length2);

                    CameraAppendHObject0 = null;
                    CameraGCStyle0 = new Tuple<string, object>("Color", "green");
                    CameraGCStyle0 = new Tuple<string, object>("DrawMode", "margin");
                    CameraAppendHObject0 = rec2;
                    CameraAppendHMessage0 = null;
                    CameraAppendHMessage0 = new HMsgEntry($"面积:{area.D}\n坐标:{row1.D:F1},{column1.D:F1}", 100, 100);
                }
                ho_Image.Dispose();
                ho_Region.Dispose();
                ModelRegion.Dispose();
                ho_RegionErosion.Dispose();
                ho_ConnectedRegions.Dispose();
                ho_SelectedRegions.Dispose();
                ho_RegionFillUp.Dispose();
                if (obj != null)
                {
                    var mp = (MPoint)obj;
                    using (var db = new DTContext(partNumber))
                    {
                        var p1 = db.WorkPoints.FirstOrDefault(p => p.Id == mp.Id);
                        if (p1 != null)
                        {
                            HTuple homMat2D;
                            HOperatorSet.ReadTuple(System.IO.Path.Combine(System.Environment.CurrentDirectory, "Calib\\MoveCameraCalibHomMat2D.tup"), out homMat2D);
                            HTuple x1, y1;
                            HOperatorSet.AffineTransPoint2d(homMat2D, row1, column1, out x1, out y1);
                            var point = db.XYZPoints.FirstOrDefault(p => p.Name == "CalibCamera");
                            if (point != null)
                            {
                                double x2 = x1 + p1.X - point.X + p1.ST_X;
                                double y2 = y1 + p1.Y - point.Y + p1.ST_Y;
                                double h1 = distance;
                                if (PLCModbus.Instance.Connected)
                                {
                                    var aa = PLCModbus.Instance.ReadDRegisters(100, 1);
                                    if (aa != null)
                                    {
                                        var bb = Convert.ToInt16(aa[0].ToString("X4"), 16);
                                        h1 = Math.Round(bb / 20000.0 * 280 - 140 + 300, 1);
                                    }
                                }
                                _eventAggregator.GetEvent<MessagePrintEvent>().Publish(new Common.Event.Message() { Sender = "CameraOperationDialog", Type = "DebugPosition", Content = $"{Math.Round(x2, 3)},{Math.Round(y2, 3)},{Math.Round(standZ - (h1 - distance) + p1.ST_H, 3)}" });
                                MessageBox.Show($"计算结果:\nX:{Math.Round(x2, 3)}\nY:{Math.Round(y2, 3)}\n{Math.Round(standZ - (h1 - distance) + p1.ST_H, 3)}", "信息", MessageBoxButtons.OK, MessageBoxIcon.Information);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void ExecuteFindShapModelCommand(object obj)
        {
            try
            {
                // Local iconic variables 

                HObject ho_Image, ho_Region, ho_RegionErosion;
                HObject ModelRegion, ho_ConnectedRegions, ho_SelectedRegions, ho_RegionFillUp;

                // Initialize local and output iconic variables 
                HOperatorSet.GenEmptyObj(out ho_Image);
                HOperatorSet.GenEmptyObj(out ho_Region);
                HOperatorSet.GenEmptyObj(out ModelRegion);
                HOperatorSet.GenEmptyObj(out ho_RegionErosion);
                HOperatorSet.GenEmptyObj(out ho_ConnectedRegions);
                HOperatorSet.GenEmptyObj(out ho_SelectedRegions);
                HOperatorSet.GenEmptyObj(out ho_RegionFillUp);

                HOperatorSet.ReadRegion(out ModelRegion, System.IO.Path.Combine(System.Environment.CurrentDirectory, partNumber, "ModelRegion.hobj"));
                HOperatorSet.ReduceDomain(CameraIamge0, ModelRegion, out ho_Image);
                ho_Region.Dispose();
                HOperatorSet.Threshold(ho_Image, out ho_Region, 200, 255);
                ho_RegionErosion.Dispose();
                HOperatorSet.ErosionCircle(ho_Region, out ho_RegionErosion, 1);
                ho_ConnectedRegions.Dispose();
                HOperatorSet.Connection(ho_RegionErosion, out ho_ConnectedRegions);
                ho_SelectedRegions.Dispose();
                HOperatorSet.SelectShape(ho_ConnectedRegions, out ho_SelectedRegions, "area",
                    "and", AreaMinThreshold, AreaMaxThreshold);
                ho_RegionFillUp.Dispose();
                HOperatorSet.FillUp(ho_SelectedRegions, out ho_RegionFillUp);

                HTuple number;
                HOperatorSet.CountObj(ho_SelectedRegions, out number);
                
                if (number.I > 1)
                {
                    MessageBox.Show("找到多个模板", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else if (number.I == 0)
                {
                    MessageBox.Show("未找到模板", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {

                    HTuple area = null, row = null, column = null;
                    HOperatorSet.AreaCenter(ho_SelectedRegions, out area, out row, out column);

                    HTuple row1 = null, column1 = null, phi = null, length1 = null, length2 = null;
                    HOperatorSet.SmallestRectangle2(ho_RegionFillUp, out row1, out column1, out phi, out length1, out length2);
                    HObject rec2;
                    HOperatorSet.GenEmptyObj(out rec2);
                    HOperatorSet.GenRectangle2(out rec2, row1, column1, phi, length1, length2);
                    CameraAppendHObject0 = null;
                    CameraGCStyle0 = new Tuple<string, object>("Color", "green");
                    CameraGCStyle0 = new Tuple<string, object>("DrawMode", "margin");
                    CameraAppendHObject0 = rec2;
                    CameraRepaint0 = !CameraRepaint0;
                    CameraAppendHMessage0 = null;
                    CameraAppendHMessage0 = new HMsgEntry($"面积:{area.D}\n坐标:{row1.D:F1},{column1.D:F1}", 100, 100);
                }
                ho_Image.Dispose();
                ho_Region.Dispose();
                ModelRegion.Dispose();
                ho_RegionErosion.Dispose();
                ho_ConnectedRegions.Dispose();
                ho_SelectedRegions.Dispose();
                ho_RegionFillUp.Dispose();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        void ExecuteCreateShapModelCommand()
        {
            if (MessageBox.Show("确认创建区域吗？", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
            {
                try
                {
                    ROI roi = Global.MoveCameraOperaImageViewer.DrawROI(ROI.ROI_TYPE_RECTANGLE1);
                    HRegion ModelRegion = roi.getRegion();
                    HOperatorSet.WriteRegion(ModelRegion, System.IO.Path.Combine(System.Environment.CurrentDirectory, partNumber, "ModelRegion.hobj"));
                    CameraAppendHObject0 = null;
                    CameraGCStyle0 = new Tuple<string, object>("Color", "green");
                    CameraGCStyle0 = new Tuple<string, object>("DrawMode", "margin");
                    CameraAppendHObject0 = ModelRegion;
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }
        void ExecuteCameraOperateCommand(object obj)
        {
            switch (obj.ToString())
            {
                case "拍照":
                    CameraIamge0 = Camera.Instance.GrabImage();
                    break;
                case "打开":
                    {
                        OpenFileDialog openFileDialog = new OpenFileDialog();
                        openFileDialog.Filter = "Image Files|*.png;*.bmp;*.jpg;*.tif";
                        if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                        {
                            HObject image;
                            HOperatorSet.ReadImage(out image, openFileDialog.FileName);
                            CameraIamge0 = new HImage(image);
                        }
                    }
                    break;
                case "增强":
                    {
                        try
                        {
                            CameraIamge0 = new HImage(Camera.EnhancedImage(CameraIamge0));
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
        #endregion
        #region 构造函数
        public CameraOperationDialogViewModel(IEventAggregator ea)
        {
            _eventAggregator = ea;
            _eventAggregator.GetEvent<MessagePrintEvent>().Subscribe(MessageReceived);
        }
        #endregion
        #region 功能函数
        private void MessageReceived(Common.Event.Message obj)
        {
            switch (obj.Type)
            {
                case "Select":
                    partNumber = obj.Content;
                    LoadParam();
                    Update(partNumber);
                    break;
                case "Update":
                    if (obj.Sender != "CameraOperationDialog")
                    {
                        LoadParam();
                        Update(partNumber);
                    }
                    break;
                default:
                    break;
            }
        }
        void LoadParam()
        {
            try
            {
                //Json序列化，从文件读取
                string jsonString = File.ReadAllText(System.IO.Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, partNumber, "Param.json"));
                param = JsonConvert.DeserializeObject<Param>(jsonString);
            }
            catch (Exception ex)
            {
                _eventAggregator.GetEvent<MessagePrintEvent>().Publish(new Common.Event.Message() { Sender = "CameraOperationDialog", Type = "Print", Content = ex.Message });
            }
        }
        private void Update(string partnum)
        {
            Points.Clear();
            using (var db = new DTContext(partnum))
            {
                var ps = db.WorkPoints.Where(p => p.Hand == hand).ToList();
                if (ps.Any())
                {
                    for (int i = 0; i < ps.Count; i++)
                    {
                        Points.Add(new MPoint 
                        {
                            Id = ps[i].Id,
                            Name = ps[i].Name
                        });
                    }
                }
            }
        }
        private void ContinueGrab(CancellationToken token)
        {
            while (true)
            {
                if (token.IsCancellationRequested)
                {
                    return;
                }
                var img = Camera.Instance.GrabeImageAsync();
                if (img != null)
                {
                    CameraIamge0 = img;
                }
            }
        }
        #endregion
    }
    public class MPoint
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}
